//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "aura.h"
#include "wince.h"
#include "private.h"

void _assert(const char *exp, const char *f, int ln)
{
    Aura_printf("Assertion failed: %s, file %s, line %d\n", exp, f, ln);
    __debugbreak();
}

static Aura_ECode ConvertToAuraECode(
    /* [in] */ DWORD dwError)
{
    Aura_ECode ec = AURA_NOERROR;

    switch(dwError) {
    case ERROR_SUCCESS:
        ec = AURA_NOERROR;
        break;
    case ERROR_ALREADY_EXISTS:
        ec = AURA_E_ALREADY_EXIST;
        break;
    case ERROR_BROKEN_PIPE:
    case ERROR_NO_DATA:
        ec = AURA_E_PROCESS_ALREADY_EXITED;
        break;
    case ERROR_FILE_NOT_FOUND:
    case ERROR_MOD_NOT_FOUND:
        ec = AURA_E_FILE_NOT_FOUND;
        break;
    case ERROR_NOT_OWNER:
        ec = AURA_E_NOT_OWNER;
        break;
    case ERROR_COMMITMENT_LIMIT:
    case ERROR_NOT_ENOUGH_MEMORY:
        ec = AURA_E_OUT_OF_MEMORY;
        break;
    case ERROR_INVALID_PARAMETER:
        ec = AURA_E_INVALID_ARGUMENT;
        break;
    case ERROR_MORE_DATA:
        ec = AURA_E_BUFFER_TOO_SMALL;
        break;
    default:
        Aura_printf(" (MS)Last Error: %d\n", dwError);
        ec = AURA_E_FAIL;
    }

    return ec;
}

Aura_ECode GetLastAuraECode()
{
    DWORD dwErr = GetLastError();
    return ConvertToAuraECode(dwErr);
}

void WinSysTimeConvertToAura(
    /* [in]  */ LPSYSTEMTIME pWinSystime,
    /* [out] */ Aura_SystemTime * pAuraSystime)
{
    int mon  = pWinSystime->wMonth;
    int year = pWinSystime->wYear;
    if (0 >= (int) (mon -= 2)) {// 1..12 -> 11,12,1..10
        mon += 12;              // Puts Feb last since it has leap day
        year -= 1;
    }

    ULONG t = ((((ULONG)(year/4 - year/100
                         + year/400
                         + 367*mon/12
                         + pWinSystime->wDay)
                  + year*365 - 719499) * 24
                 + pWinSystime->wHour) * 60   // now have hours
                + pWinSystime->wMinute) * 60  // now have minutes
               + pWinSystime->wSecond;        // finally seconds
    pAuraSystime->seconds = t;
    pAuraSystime->microseconds = pWinSystime->wMilliseconds * 1000;

    return;
}

void AuraSysTimeConvertToWin(
    /* [in]  */ Aura_SystemTime * pAuraSysTime,
    /* [out] */ LPSYSTEMTIME pWinSysTime)
{
#define IS_LEAP_YEAR(x)   ((x)% 400 == 0 || (!((x) & 3) && (x) % 100 != 0))

    UCHAR s_DaysInMonth1[] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
    UCHAR s_DaysInMonth0[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    pWinSysTime->wMilliseconds = (WORD)(pAuraSysTime->microseconds/1000);
    ULONG tm = (ULONG)(pAuraSysTime->seconds);//unit is second
    pWinSysTime->wSecond    = (WORD) (tm % 60);
    tm /= 60;
    pWinSysTime->wMinute    = (WORD) (tm % 60);
    tm /= 60;
    pWinSysTime->wHour      = (WORD) (tm % 24);
    tm /= 24;   // tm becomes day
    pWinSysTime->wDayOfWeek = (WORD) ((tm + 4) % 7);        // it's Thursday on 1/1/1970

    // count from 1970. year 2100 will be count as a leap year falsely
    // due to simplify of IS_LEAP_YEAR algorithm.
    //
    UINT year = 70;
    while (1) {
        if (IS_LEAP_YEAR(year + 300)) {
            if (tm < 366)
                break;
            else
                tm -= 366;
        }
        else {
            if (tm < 365)
                break;
            else
                tm -= 365;
        }
        year++;
    }
    UINT month = 1;
    UCHAR *  DaysInMonth = IS_LEAP_YEAR(year + 300) ? s_DaysInMonth1 : s_DaysInMonth0;
    while (1) {
        if (tm < DaysInMonth[month])
            break;
        else
            tm -= DaysInMonth[month];
        month++;
    }
    pWinSysTime->wYear  = year + 1900;
    pWinSysTime->wMonth = month;
    pWinSysTime->wDay   = (WORD)++tm;

    return;
}

Aura_ThreadPriority ConvertToAuraPriority(
    /* [in]  */ int priority)
{
    Aura_ThreadPriority pri;

    switch (priority) {
        case THREAD_PRIORITY_TIME_CRITICAL:
        case THREAD_PRIORITY_HIGHEST:
            pri = Aura_ThreadPriority_Highest;
            break;
        case THREAD_PRIORITY_ABOVE_NORMAL:
            pri = Aura_ThreadPriority_AboveNormal;
            break;
        case THREAD_PRIORITY_NORMAL:
            pri = Aura_ThreadPriority_Normal;
            break;
        case THREAD_PRIORITY_BELOW_NORMAL:
            pri = Aura_ThreadPriority_BelowNormal;
            break;
        case THREAD_PRIORITY_LOWEST:
        case THREAD_PRIORITY_ABOVE_IDLE:
        case THREAD_PRIORITY_IDLE:
            pri = Aura_ThreadPriority_Lowest;
            break;
        default:
            assert(0); // should never happen.
            break;
    }
    return pri;
}

int ConvertToWinPriority(
    /* [in]  */ Aura_ThreadPriority priority)
{
    int pri;
    if (priority < Aura_ThreadPriority_Lowest) {
        pri = THREAD_PRIORITY_ABOVE_IDLE;
    }
    else if (priority < Aura_ThreadPriority_BelowNormal) {
        pri = THREAD_PRIORITY_LOWEST;
    }
    else if (priority < Aura_ThreadPriority_Normal) {
        pri = THREAD_PRIORITY_BELOW_NORMAL;
    }
    else if (priority < Aura_ThreadPriority_AboveNormal) {
        pri = THREAD_PRIORITY_ABOVE_NORMAL;
    }
    else if (priority < Aura_ThreadPriority_Highest) {
        pri = THREAD_PRIORITY_ABOVE_NORMAL;
    }
    else {
        pri = THREAD_PRIORITY_HIGHEST;
    }
    return pri;
}

DWORD ConvertToWinAllocateType(
    /* [in]  */ Aura_MemoryMapFlags flags)
{
    DWORD allocateType = 0;

    // MemoryMap_Private:
    // MemoryMap_Shared:
    // MemoryMap_Fixed:
    // MemoryMap_Upgrow:
    // MemoryMap_Downgrow:

    allocateType = MEM_RESERVE | MEM_COMMIT;

    return allocateType;
}

DWORD ConvertToWinMemoryProection(
    /* [in]  */ Aura_MemoryProtection protect)
{
    DWORD dwProtect = 0;

    switch (protect) {
        case Aura_MemoryProtection_Read:
            dwProtect = PAGE_READONLY;
            break;
        case Aura_MemoryProtection_Write:
            dwProtect = PAGE_READWRITE;
            break;
        case Aura_MemoryProtection_Exec:
            dwProtect = PAGE_EXECUTE;
            break;
        case Aura_MemoryProtection_RW:
            dwProtect = PAGE_READWRITE;
            break;
        case Aura_MemoryProtection_RX:
            dwProtect = PAGE_EXECUTE_READ;
            break;
        case Aura_MemoryProtection_RWX:
            dwProtect = PAGE_EXECUTE_READWRITE;
            break;
        default:
            dwProtect = PAGE_READONLY;
            break;
    }
    return dwProtect;
}

Aura_Millisecond32 ConvertToAuraMilliseconds(
    /* [in] */ LPFILETIME pFileTime)
{
    UINT64 calcTime;
    const INT64 MSECS_TO_NS = 1000000;    /* 10^6 */

    calcTime = (UINT64)pFileTime->dwLowDateTime \
                 + ((UINT64)pFileTime->dwHighDateTime << 32);
    calcTime *= 100;    /* to NS */
    return (Aura_Millisecond32)(calcTime / MSECS_TO_NS);
}

DWORD ConvertToWinFileAccess(
    /* [in]  */ Aura_MemoryProtection protect)
{
    DWORD dwProtect = 0;

    switch (protect) {
        case Aura_MemoryProtection_Read:
        case Aura_MemoryProtection_Exec:
        case Aura_MemoryProtection_RX:
            dwProtect = FILE_MAP_READ;
            break;
        case Aura_MemoryProtection_Write:
            dwProtect = FILE_MAP_WRITE;
            break;

        case Aura_MemoryProtection_RW:
        case Aura_MemoryProtection_RWX:
            dwProtect = FILE_MAP_WRITE;
            break;
        default:
            dwProtect = FILE_MAP_READ;
            break;
    }
    return dwProtect;
}

